package com.mop.springcloud.corebase;

import com.mop.springcloud.corebase.bean.ServiceInfo;
import com.mop.springcloud.corebase.listener.NotificationHook;
import com.mop.springcloud.corebase.listener.ShutdownListener;
import com.mop.springcloud.corebase.listener.def.DefaultNotificationHook;
import org.springframework.boot.ansi.AnsiColor;
import org.springframework.boot.ansi.AnsiOutput;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Class Name: MopApplicationInitializer
 * Create Date: 18-3-15 下午1:47
 * Creator: Chim·Zigui
 * Version: v1.0
 * Updater:
 * Date Time:
 * Description:
 * <p>
 * 猫扑使用的核心应用初始化器
 * <p>
 * 该初始化器在Auto配置的有默认初始化器，在服务/应用启动的时候，用于注入各类的监听回调
 *
 * @see com.mop.springcloud.corebase.config.DefaultCoreMvcConfiguration
 */
public abstract class MopApplicationInitializer {

    /**
     * Console Banner
     */
    private static final String BANNER_TEXT;
    /**
     * Starter Print Info
     */
    private static String STARTER_INFO_PRINT_DATA = null;
    /**
     * Indicate Mop Application Initializer Enabled
     */
    private static Boolean MOP_APPLICATION_INITIALIZER_ENABLE = false;

    static {
        // Initialize mop starter banner.
        InputStream bannerStream = MopApplicationInitializer.class.getClassLoader().getResourceAsStream("mop_banner.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(bannerStream));
        String line;
        StringBuilder builder = new StringBuilder();
        try {
            while ((line = reader.readLine()) != null) {
                builder.append("| ").append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Fill banner variable.
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm");
        BANNER_TEXT = builder.toString()
                .replaceAll("\\( v", "(" + dateFormat.format(new Date()) + " v");
    }

    /**
     * 配置服务/应用停止监听器，一般用于在结束一个应用或者服务的时候，等待未完成的任务或服务执行完成，或者补充持久化数据等防止数据丢失的
     * 回调
     *
     * @return ShutdownListener 停止监听器的实现类
     */
    public ShutdownListener getShutdownListener() {
        return null;
    }

    /**
     * 配置服务/应用告警通知监听器，用于服务启动必要位置进行告警通知
     *
     * @return NotificationHook 告警监听实现类
     */
    public NotificationHook getNotificationHook() {
        return new DefaultNotificationHook();
    }

    /**
     * 打印服务应用的基本启动信息
     *
     * @param info 需要打印的服务信息
     * @return 信息
     */
    public final String printAppStartInfo(ServiceInfo info) {
        AtomicReference<StringBuilder> infoBuilder = new AtomicReference<>(new StringBuilder());
        infoBuilder.get().append("======================================== Mop Service/App Starter Info ========================================")
                .append("\n");

        infoBuilder.get().append(BANNER_TEXT);
        infoBuilder.get().append("| Server PORT:\t").append(info.getServerPort()).append("\n");
        infoBuilder.get().append("| Service/App PID:\t").append(info.getPid()).append("\n");

        String tag = "A".equals(info.getServiceTag()) ? "A (Def)" : info.getServiceTag();
        infoBuilder.get().append("| Service/App Tag:\t").append(tag).append("\n");

        infoBuilder.get().append("| Java Runtime:\t").append(info.getJavaRuntime()).append("\n");
        infoBuilder.get().append("| Service/App Start Time:\t").append(new Date(info.getBeginTime())).append("\n");
        infoBuilder.get().append("| Spring Application Name:\t").append(info.getApplicationName()).append("\n");
        infoBuilder.get().append("| Spring Profiles Active:\t")
                .append(System.getProperty("spring.profiles.active", "default")).append("\n");
        infoBuilder.get().append("| Had Shutdown Listener Registered:\t").append(info.getShutdownListenerRegistered()).append("\n");
        infoBuilder.get().append("| Had Registered Notifier:\t").append(info.getRegisterNotificationHook()).append("\n");
        infoBuilder.get().append("| ").append("\n");
        Map<String, Object> extStartInfo = extStartInfo();
        if (extStartInfo != null && extStartInfo.size() > 0) {
            infoBuilder.get().append("|---------\n");
            for (String key : extStartInfo.keySet()) {
                infoBuilder.get().append("| ").append(key).append(":\t").append(extStartInfo.get(key)).append("\n");
            }
        }
        infoBuilder.get().append("| Start Time Consuming:\t").append(info.getStarterDuration()).append(" ms\n");
        infoBuilder.get().append("======================================== Mop Service/App Starter Info ========================================");
        STARTER_INFO_PRINT_DATA = infoBuilder.toString();
        return AnsiOutput.toString(AnsiColor.GREEN, STARTER_INFO_PRINT_DATA, AnsiColor.DEFAULT);
    }

    /**
     * 打印服务应用的基本停止信息
     *
     * @param info 需要打印的停止信息
     * @return 信息
     */
    public final String printAppEndInfo(ServiceInfo info) {
        AtomicReference<StringBuilder> infoBuilder = new AtomicReference<>(new StringBuilder());
        infoBuilder.get().append("======================================== Mop Service/App Stopped Info ========================================")
                .append("\n");

        infoBuilder.get().append("| Server PORT:\t").append(info.getServerPort()).append("\n");
        infoBuilder.get().append("| Service/App PID:\t").append(info.getPid()).append("\n");
        infoBuilder.get().append("| Service/App Tag:\t").append(info.getServiceTag()).append("\n");
        infoBuilder.get().append("| Java Runtime:\t").append(info.getJavaRuntime()).append("\n");
        infoBuilder.get().append("| Service/App Start Time:\t").append(new Date(info.getBeginTime())).append("\n");
        infoBuilder.get().append("| Service/App Stopped Time:\t").append(new Date(info.getEndTime())).append("\n");
        infoBuilder.get().append("| Spring Application Name:\t").append(info.getApplicationName()).append("\n");
        infoBuilder.get().append("| Spring Profiles Active:\t")
                .append(System.getProperty("spring.profiles.active", "default")).append("\n");
        infoBuilder.get().append("| Had Registered Shutdown Listener:\t").append(info.getShutdownListenerRegistered()).append("\n");
        infoBuilder.get().append("| Had Registered Notifier:\t").append(info.getRegisterNotificationHook()).append("\n");

        BigDecimal duration = new BigDecimal((info.getEndTime() - info.getBeginTime()) / 60000.0);
        infoBuilder.get()
                .append("| Running Duration:\t")
                .append(duration.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
                .append(" min").append("\n");

        infoBuilder.get().append("| ").append("\n");
        Map<String, Object> extEndInfo = extEndInfo();
        if (extEndInfo != null && extEndInfo.size() > 0) {
            infoBuilder.get().append("|---------\n");
            for (String key : extEndInfo.keySet()) {
                infoBuilder.get().append("| ").append(key).append(":\t").append(extEndInfo.get(key)).append("\n");
            }
        }
        infoBuilder.get().append(BANNER_TEXT);
        infoBuilder.get().append("======================================== Mop Service/App Stopped Info ========================================");
        return AnsiOutput.toString(AnsiColor.BRIGHT_RED, infoBuilder.toString(), AnsiColor.DEFAULT);
    }


    public static Boolean isMopApplicationInitializerEnable() {
        return MOP_APPLICATION_INITIALIZER_ENABLE;
    }

    public static void setMopApplicationInitializerEnable(Boolean mopApplicationInitializerEnable) {
        MOP_APPLICATION_INITIALIZER_ENABLE = mopApplicationInitializerEnable;
    }

    public String getStarterInfoPrintData() {
        return STARTER_INFO_PRINT_DATA;
    }

    /**
     * 扩展的服务启动信息
     *
     * @return 启动键值信息，Override
     */
    public Map<String, Object> extStartInfo() {
        return null;
    }

    /**
     * 扩展的服务结束信息
     *
     * @return 停止键值信息，Override
     */
    public Map<String, Object> extEndInfo() {
        return null;
    }

}
